/**
 * Thinking in java 
 *  2018/08/01
 */
package com.dzb.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


/**
 * @author dzb
 * @date 2018年8月15日 上午11:50:47
 * @description   nio底层网络协议链接
 * @version 1.0.0
 */
public class NioServer {
	
	public static Selector selector;

	//线程池
	public static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS,
			new LinkedBlockingQueue<Runnable>());

	private static ServerSocketChannel serverSocketChannel;

	private static final int port = 8080;
	
	public static void main(String[] args) {
		
		try {
			//打开通道
			serverSocketChannel = ServerSocketChannel.open();
			//绑定监听端口
			serverSocketChannel.socket().bind(new InetSocketAddress(port));
			serverSocketChannel.configureBlocking(false);//声明非阻塞
			System.out.println("NIO启动:" + port);
			//创建reactor 线程
			Selector selector = Selector.open();
			//new Thread(new Reactor)
			//多路复用
			SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
			//多路复用监听新客户端链接
			while (true) {

				// 根据查询器已有的条件去查询(去操作系统底层管理socket连接的地方查询)
				// 查询超时的时间是1秒钟，如果1秒内没查到结果，继续执行下面的代码
				selector.select(1000);
				int num = selector.select();
				Set<SelectionKey> selectedKeys = selector.selectedKeys();
				// 遍历查询结果
				Iterator<SelectionKey> iter = selectedKeys.iterator();
				while (iter.hasNext()) 
				{
					// 被封装的查询结果
					SelectionKey key1 = iter.next();
					if(key1.isValid())
					{
						if(key1.isAcceptable())// 如果是Acceptable，表明查询条件是OP_ACCEPT，代表有新的连接建立了
						{
							// 处理连接
							// 在服务端通道中，取出新的socket连接
							SocketChannel chan = serverSocketChannel.accept();
							// 设置为非阻塞模式
							chan.configureBlocking(false);
							// 在新的socket连接上，增加一个查询器（复用上面已有的查询器）
							// 并且，查询条件是：OP_READ 有数据传输
							chan.register(selector, SelectionKey.OP_READ);
	
							System.out.println("有新的连接啦，当前线程数量:" + threadPoolExecutor.getActiveCount());
						}
						else if(key1.isReadable()) // 如果是Acceptable，表明这个查询结果所使用的查询条件是OP_READ，代表某个连接有数据传输过来了
						{
							// 从查询结果中，获取到对应的有数据传输的socket连接
							SocketChannel socketChannel = (SocketChannel) key.channel();
							// 取消查询，表示这个socket连接当前正在被处理，不需要被查询到
							key.cancel();
							// 设置为非阻塞模式
							socketChannel.configureBlocking(false);
							threadPoolExecutor.execute(new NioSocketProcessor(socketChannel));//执行数据处理
						}
					}
				}
				// 清除查询结果
				selectedKeys.clear();
				selector.selectNow();
			}
		
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	

	

}
